package org.geektimes.configuration.microprofile.better.config.source;

import org.eclipse.microprofile.config.spi.ConfigBuilder;
import org.eclipse.microprofile.config.spi.ConfigSource;

import java.util.*;
import java.util.function.Consumer;

import static java.util.Collections.sort;

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @Author: menglinggang
 * @Date: 2021-03-30
 * @Time: 2:49 下午
 */
public class ConfigSources implements Iterable<ConfigSource> {

    private List<ConfigSource> configSourceList = new ArrayList<>();

    private ClassLoader classLoader;

    private boolean addDefaultSources;

    private boolean addDiscoveredSources;

    public ConfigSources(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public Iterator<ConfigSource> iterator() {
        return configSourceList.iterator();
    }

    public void addDefaultSources() {
        if (addDefaultSources == true) {
            return;
        }
        appConfigSources(SystemEnvConfigSource.class, SystemPropertiesConfigSource.class);
        addDefaultSources = true;
    }

    private void appConfigSources(Class<? extends ConfigSource>... configSourceClasses) {
        addConfigSources(Arrays.stream(configSourceClasses).map(this::newInstance).toArray(ConfigSource[]::new));
    }

    public void addConfigSources(ConfigSource... configSources) {
        addConfigSources(Arrays.asList(configSources));
    }

    private void addConfigSources(Iterable<ConfigSource> configSources) {
        configSources.forEach(this.configSourceList::add);
        sort(this.configSourceList, ConfigSourceOrdinalComparator.INSTANCE);
    }

    public void addDiscoveredSources() {
        if (addDiscoveredSources == true) {
            return;
        }
        ServiceLoader<ConfigSource> sources = ServiceLoader.load(ConfigSource.class, getClassLoader());
        addConfigSources(sources);
        addDiscoveredSources = true;
    }

    private ConfigSource newInstance(Class<? extends ConfigSource> configSourceClass) {
        ConfigSource instance = null;
        try {
            instance = configSourceClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
        return instance;
    }

    public ClassLoader getClassLoader() {
        return classLoader == null ? this.getClassLoader() : classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }


}
